package com.chenjl.transport.support;

import java.net.InetSocketAddress;
import java.util.concurrent.ExecutionException;

import com.chenjl.Constant;
import com.chenjl.transport.AbstractClient;
import com.chenjl.transport.HookChannelHandler;
import com.chenjl.transport.codec.ObjectDecoder;
import com.chenjl.transport.codec.ObjectEncoder;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
/**
 * 
 * 2016-9-2 13:50:00
 * @author chenjinlong
 */
public class NettyClient extends AbstractClient {
	private String serverAddr = null;
	private volatile Channel channel = null;
	private EventLoopGroup group = null;
	private Bootstrap bootstrap = null;
	
	public NettyClient(String serverAddr,HookChannelHandler hookChannelHandler) {
		this.serverAddr = serverAddr;
		group = new NioEventLoopGroup();
		bootstrap = new Bootstrap();
		bootstrap.group(group);
		bootstrap.channel(NioSocketChannel.class);
		bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
		bootstrap.option(ChannelOption.TCP_NODELAY, true);
		
		ClientHandler clientHandler = new ClientHandler(hookChannelHandler);
		bootstrap.handler(new ChannelInitializer<SocketChannel>() {
             @Override
             public void initChannel(SocketChannel socketChannel) throws Exception {
                 ChannelPipeline channelPipeline = socketChannel.pipeline();
                 
                 channelPipeline.addLast(new ObjectEncoder());
                 channelPipeline.addLast(new ObjectDecoder());
                 channelPipeline.addLast(clientHandler);
             }
         });
	}
	@Override
	public void connect() {
		try {
			ChannelFuture channelFuture = bootstrap.connect(serverAddr,Constant.PORT).sync();
			channelFuture.get();
	        channel = channelFuture.channel();
	        logger.info("conect to server success : {}",serverAddr);
		}
		catch (InterruptedException e) {
			e.printStackTrace();
		}
		catch (ExecutionException e) {
			e.printStackTrace();
		}
	}
	@Override
	public void reconnect() {
		
	}
	@Override
	public boolean isConnect() {
		return channel!=null && channel.isActive();
	}
	@Override
	public void close() {
		if(close) {
			return;
		}
		group.shutdownGracefully();
		if(channel!=null && channel.isActive()) {
			channel.close();
		}
		close = true;
	}
	@Override
	public void send(Object object, boolean sent) {
		logger.info("send a messge begin");
		ChannelFuture channelFuture = channel.writeAndFlush(object);
		if(sent) {
			try {
				channelFuture.get();
				logger.info("send a messge complete");
			} 
			catch (InterruptedException e) {
				e.printStackTrace();
			}
			catch (ExecutionException e) {
				e.printStackTrace();
			}
		}
	}
	@Override
	public InetSocketAddress getLocalAddress() {
		return (InetSocketAddress) channel.localAddress();
	}
	@Override
	public InetSocketAddress getRemoteAddress() {
		return (InetSocketAddress) channel.remoteAddress();
	}
}